package com.liqing.movecomment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.pagehelper.Constant;
import com.liqing.movecomment.dao.MoveDao;
import com.liqing.movecomment.entity.Move;
import com.liqing.movecomment.entity.Score;
import com.liqing.movecomment.dao.ScoreDao;
import com.liqing.movecomment.entity.User;
import com.liqing.movecomment.exception.CustomException;
import com.liqing.movecomment.exception.LdException;
import com.liqing.movecomment.service.MoveService;
import com.liqing.movecomment.service.ScoreService;
import com.liqing.movecomment.service.TagService;
import com.liqing.movecomment.util.SwapePageUtil;
import com.liqing.movecomment.util.ThreadLocalUtils;
import com.liqing.movecomment.vo.ScoreTagVo;
import com.liqing.movecomment.vo.ScoreVo;
import io.swagger.models.auth.In;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
@Transactional
@Service("scoreService")
public class ScoreServiceImpl implements ScoreService {
    @Resource
    private ScoreDao scoreDao;


    @Resource
    private MoveService moveService;

    @Resource
    private MoveDao moveDao;
    @Autowired
    private TagService tagService;


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ScoreVo queryById(Integer id) {
        return copyEToVo(this.scoreDao.selectById(id));
    }

    /**
     * 分页查询
     *
     * @param page 页码
     * @param size 页大小
     * @return 查询结果
     */
    @Override
    public PageInfo<ScoreVo> queryAll(Integer page, Integer size) {
        PageHelper.startPage(page, size);
        LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<>();

        User user = (User) ThreadLocalUtils.get();
        wrapper.eq(Score::getUserId, user.getId());
        List<Score> list = this.scoreDao.selectList(wrapper);

        List<ScoreVo> scoreVoList = copyList(list);


        return SwapePageUtil.swapePage(list, scoreVoList);
    }

    private List<ScoreVo> copyList(List<Score> list) {
        List<ScoreVo> scoreVoList = new ArrayList<>();

        list.stream().parallel().forEach(score -> {
            scoreVoList.add(copyEToVo(score));
        });
        return scoreVoList;
    }

    private ScoreVo copyEToVo(Score score) {
        final ScoreVo scoreVo = new ScoreVo();

        BeanUtils.copyProperties(score, scoreVo);

        scoreVo.setMoveVo(moveService.queryById(score.getMoveId()));
        scoreVo.setTag(tagService.queryById(score.getTagId()));
        return scoreVo;
    }

    /**
     * 新增数据
     *
     * @param score 实例对象
     * @return 实例对象
     */
    @Override
    public Score insert(Score score) {

        User user = (User) ThreadLocalUtils.get();

        //查询是否有 有过评分
        new LambdaQueryChainWrapper<>(scoreDao)
                .eq(Score::getUserId, user.getId())
                .eq(Score::getMoveId, score.getMoveId())
                .eq(Score::getTagId, score.getTagId())
                .oneOpt().ifPresent(s -> {
                    throw new LdException(11, "你已评分过，无需再评");
                });
        score.setUserId(user.getId());
        this.scoreDao.insert(score);
        // 开始修改评分

        Double averageScore = 0.0;
        final Move move = moveDao.selectById(score.getMoveId());
        move.setId(score.getMoveId());
        List<Double> doubles = scoreDao.selectScoreByMoveId(score.getMoveId());

        if (ObjectUtils.isEmpty(doubles) || doubles.size() < 3) {
            double all = doubles.stream().reduce(0D, Double::sum);
            averageScore = all / doubles.size();
        } else {
            double max = doubles.stream().max(Double::compareTo).orElse(0D);
            double min = doubles.stream().min(Double::compareTo).orElse(0D);
            double all = doubles.stream().reduce(0D, Double::sum) - max - min;
            averageScore = all / doubles.size();
        }
        final List<Integer> collect = scoreDao.selectList(
                        new LambdaQueryWrapper<Score>().eq(Score::getMoveId, score.getMoveId()))
                .stream().
                map(Score::getUserId)
                .distinct()
                .collect(Collectors.toList());

        move.setScore(averageScore);
        Integer people = collect.size();
        move.setPeople(people + 1);//todo
        moveDao.updateById(move);


        return score;
    }

    /**
     * 修改数据
     *
     * @param score 实例对象
     * @return 实例对象
     */
    @Override
    public Score update(Score score) {
        this.scoreDao.updateById(score);
        return this.scoreDao.selectById(score.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.scoreDao.deleteById(id) > 0;
    }


    @Override
    public Score getScore(Integer movieId, Integer tagId) {
        User user = (User) ThreadLocalUtils.get();
        Score score = scoreDao.selectOne(new LambdaQueryWrapper<Score>()
                .eq(Score::getMoveId, movieId)
                .eq(Score::getTagId, tagId)
                .eq(Score::getUserId, user.getId()));
        return score;
    }


    @Override
    public List<ScoreTagVo> getScoreByMovieId(Integer movieId) {

        List<Score> scores = scoreDao.getScoreByMovieId(movieId);
        List<ScoreTagVo> collect = scores.stream().map(score -> {
            ScoreTagVo scoreTagVo = new ScoreTagVo();
            scoreTagVo.setScore(score.getScore());
            scoreTagVo.setTagName(tagService.queryById(score.getTagId()).getTagName());
            return scoreTagVo;
        }).collect(Collectors.toList());
        return collect;
    }
}
